/**
    @user: lcz
    @date: 2020/9/10
    @op:
**/
package conf

import (
	"fmt"
	log "github.com/sirupsen/logrus"
	"os"
	"runtime"
	"strings"
)

var Log *log.Logger

func InitLog() {
	Log = log.New()

	// 为当前logrus实例设置消息的输出，同样地，
	Log.Out = os.Stdout
	// 可以设置logrus实例的输出到任意io.writer
	// 可以设置像文件等任意`io.Writer`类型作为日志输出
	// file, err := os.OpenFile(&quot;logrus.log&quot;, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	// if err == nil {
	//  log.Out = file
	// } else {
	//  log.Info(&quot;Failed to log to file, using default stderr&quot;)
	// }

	// gin使用
	//f,_ := os.Create("./gin.log")
	//Log.Out = f
	//gin.DefaultWriter = Log.Out

	// 日志等级
	// Log.Level = info

	// 为当前logrus实例设置消息输出格式为json格式。
	// 同样地，也可以单独为某个logrus实例设置日志级别和hook，这里不详细叙述。
	//Log.Formatter = &log.JSONFormatter{}

	// 钩子
	log.AddHook(lineHook{})

}


// line number hook for log the call context,
type lineHook struct {
	Field  string
	// skip为遍历调用栈开始的索引位置
	Skip   int
	levels []log.Level
}

// Levels implement levels
func (hook lineHook) Levels() []log.Level {
	return log.AllLevels
}

// Fire implement fire
func (hook lineHook) Fire(entry *log.Entry) error {
	entry.Data[hook.Field] = findCaller(hook.Skip)
	return nil
}

func findCaller(skip int) string {
	file := ""
	line := 0
	var pc uintptr
	// 遍历调用栈的最大索引为第11层.
	for i := 0; i < 11; i++ {
		file, line, pc = getCaller(skip + i)
		// 过滤掉所有logrus包，即可得到生成代码信息
		if !strings.HasPrefix(file, "logrus") {
			break
		}
	}

	fullFnName := runtime.FuncForPC(pc)

	fnName := ""
	if fullFnName != nil {
		fnNameStr := fullFnName.Name()
		// 取得函数名
		parts := strings.Split(fnNameStr, ".")
		fnName = parts[len(parts)-1]
	}

	return fmt.Sprintf("%s:%d:%s()", file, line, fnName)
}

func getCaller(skip int) (string, int, uintptr) {
	pc, file, line, ok := runtime.Caller(skip)
	if !ok {
		return "", 0, pc
	}
	n := 0

	// 获取包名
	for i := len(file) - 1; i > 0; i-- {
		if file[i] == '/' {
			n++
			if n >= 2 {
				file = file[i+1:]
				break
			}
		}
	}
	return file, line, pc
}